#include "EDBaseAfx.h"
#include "JSHelper.h"
#include "json.h"
#pragma comment(lib,"json.lib")

#define GP_TYPE_BYTES "#byte/"
#define GP_TYPE_INT64 "#i64/"

JSHandle::JSHandle() : m_jsonValue(NULL)
{
}

JSHandle::JSHandle(const JSHandle& src) : m_jsonValue(src.m_jsonValue)
{
}

JSHandle::~JSHandle()
{
	m_jsonValue = NULL;
}

bool JSHandle::isValid() const
{
	return NULL != m_jsonValue;
}

bool JSHandle::isEqual(const JSHandle& other) const
{
	return (m_jsonValue == other.m_jsonValue);
}

JSHandle::JsonType JSHandle::getType() const
{
	JsonType jsonType = JsonNull;
	switch (m_jsonValue->type())
	{
	case Json::nullValue:
		jsonType = JsonNull;
		break;
	case Json::intValue:
		jsonType = JsonInt;
		break;
	case Json::uintValue:
		jsonType = JsonUInt;
		break;
	case Json::realValue:
		jsonType = JsonDouble;
		break;
	case Json::stringValue: 
		{
			jsonType = JsonString;
			//
			LPCSTR pszString = toStringA();
			if (IsValidString(pszString))
			{
				if (0 == _strnicmp(pszString, GP_TYPE_INT64, strlen(GP_TYPE_INT64))) 
				{
					jsonType = JsonInt64;
				}
				else if (0 == _strnicmp(pszString, GP_TYPE_BYTES, strlen(GP_TYPE_BYTES))) 
				{
					jsonType = JsonByte;
				}
			}
		} break;
	case Json::booleanValue:
		jsonType = JsonBool;
		break;
	case Json::arrayValue:
		jsonType = JsonArray;
		break;
	case Json::objectValue:
		jsonType = JsonObject;
		break;
	}
	return jsonType;
}

bool JSHandle::operator!() const
{
	return isValid() && isNull();
}

bool JSHandle::operator ==(const JSHandle& other) const
{
	return m_jsonValue->operator ==(*other.m_jsonValue);
}

bool JSHandle::operator !=(const JSHandle& other) const
{
	return m_jsonValue->operator !=(*other.m_jsonValue);
}

JSHandle& JSHandle::operator=(const JSHandle& src)
{
	if (m_jsonValue) 
	{
		if (src.m_jsonValue)
			m_jsonValue->operator = (*src.m_jsonValue);
	} 
	else
	{
		m_jsonValue = src.m_jsonValue;
	}
	return *this;
}

bool JSHandle::putBool(bool data)
{
	m_jsonValue->operator = (data);
	return true;
}

bool JSHandle::putInt(int data)
{
	m_jsonValue->operator = (data);
	return true;
}

bool JSHandle::putUInt(unsigned __int32 data)
{
	m_jsonValue->operator = (data);
	return true;
}

bool JSHandle::putInt64(signed __int64 data)
{
	std::string strA;
	EDBASE::Format(strA,"#i64/%I64d", data);
	m_jsonValue->operator = (strA.c_str());

	return true;
}

bool JSHandle::putUInt64(unsigned __int64 data)
{
	std::string strA;
	EDBASE::Format(strA,"#i64/%I64u", data);
	m_jsonValue->operator = (strA.c_str());

	return true;
}

bool JSHandle::putDouble(double data)
{
	m_jsonValue->operator = (data);
	return true;
}

bool JSHandle::putString(LPCSTR data)
{
	if (IsValidString(data)) 
	{
		m_jsonValue->operator = (data);
	} 
	else
	{
		Json::Value jons_null("");
		m_jsonValue->swap(jons_null);
	}
	return true;
}

bool JSHandle::putStringW(LPCWSTR data)
{
	if (IsValidString(data)) 
	{
		std::string strUTF8 = EDBASE::w2u(data);
		m_jsonValue->operator = (strUTF8.c_str());
	} 
	else
	{
		Json::Value jons_null("");
		m_jsonValue->swap(jons_null);
	}

	return true;
}

bool JSHandle::putUTF8String(const char* data)
{
	return putString(data);
}

bool JSHandle::putBytes(const void* data, int size)
{
	bool bRet = false;
	if (data && size > 0) 
	{
		std::string strPut("#byte/");
		std::string strBase64 = EDBASE::Base64Encode((const BYTE*)data, size);
		strPut.append(strBase64);
		m_jsonValue->operator = (strPut.c_str());
		bRet = true;
	}
	return bRet;
}

bool JSHandle::getBytes(unsigned char* pbOut, int &nSize)
{
	return toBytes(pbOut, nSize);
}

JSHandle& JSHandle::operator=(bool bValue)
{
	putBool(bValue);
	return *this;
}

JSHandle& JSHandle::operator=(int iValue)
{
	putInt(iValue);
	return *this;
}

JSHandle& JSHandle::operator=(unsigned int uValue)
{
	putUInt(uValue);
	return *this;
}

JSHandle& JSHandle::operator=(signed __int64 i64Value)
{
	putInt64(i64Value);
	return *this;
}

JSHandle& JSHandle::operator=(unsigned __int64 u64Value)
{
	putUInt64(u64Value);
	return *this;
}

JSHandle& JSHandle::operator=(double dValue)
{
	putDouble(dValue);
	return *this;
}

JSHandle& JSHandle::operator=(LPCSTR pszValue)
{
	putString(pszValue);
	return *this;
}

JSHandle& JSHandle::operator=(LPCWSTR pszValue)
{
	putStringW(pszValue);
	return *this;
}

bool JSHandle::isNull() const
{
	return getType() == JsonNull;
}

bool JSHandle::isBool() const
{
	return getType() == JsonBool;
}

bool JSHandle::isInt() const
{
	return getType() == JsonInt;
}

bool JSHandle::isUInt() const
{
	return getType() == JsonUInt;
}

bool JSHandle::isInt64() const
{
	return getType() == JsonInt64;
}

bool JSHandle::isDouble() const
{
	return getType() == JsonDouble;
}

bool JSHandle::isString() const
{
	return getType() == JsonString;
}

bool JSHandle::isArray() const
{
	return getType() == JsonArray;
}

bool JSHandle::isObject() const
{
	return getType() == JsonObject;
}

bool JSHandle::isBytes() const
{
	return getType() == JsonByte;
}

LPCSTR JSHandle::toStringA() const
{
	if (m_jsonValue->isString()) 
	{
		return m_jsonValue->asCString();
	}
	return NULL;
}

LPCWSTR JSHandle::toStringW() const
{
	if (m_jsonValue->isString())
	{
		return m_jsonValue->asCStringW();
	}
	return NULL;
}

int JSHandle::toInt() const
{
	return m_jsonValue->asInt();
}

unsigned int JSHandle::toUInt() const
{
	return m_jsonValue->asUInt();
}

signed __int64 JSHandle::toInt64() const
{
	LPCSTR i64String = m_jsonValue->asCString();
	if (IsValidString(i64String) && 0 == _strnicmp(i64String, "#i64/", 5))
	{
		return _atoi64(i64String+5);
	}
	return 0;
}

unsigned __int64 JSHandle::toUInt64() const
{
	return (unsigned __int64)toInt64();
}

double JSHandle::toDouble() const
{
	return m_jsonValue->asDouble();
}

bool JSHandle::toBool() const
{
	return m_jsonValue->asBool();
}

int JSHandle::arraySize() const
{
	return m_jsonValue->isArray() ? m_jsonValue->size() : 0;
}

bool JSHandle::empty() const
{
	return m_jsonValue->empty();
}

void JSHandle::swap(JSHandle& other)
{
	m_jsonValue->swap(*other.m_jsonValue);
}

void JSHandle::clear()
{
	m_jsonValue->clear();
}

void JSHandle::resize(int size)
{
	m_jsonValue->resize(size);
}

JSHandle JSHandle::operator[](int index)
{
	JSHandle jsonHanlde;
	Json::Value& refJson = m_jsonValue->operator [](index);
	jsonHanlde.m_jsonValue = &refJson;	
	return jsonHanlde;
}

JSHandle JSHandle::append(const JSHandle& value)
{
	JSHandle refJson(*this);
	Json::Value*& refJsonData = const_cast<Json::Value*&>(refJson.m_jsonValue);
	refJsonData = &m_jsonValue->append(*value.m_jsonValue);
	return refJson;
}

JSHandle JSHandle::operator[](const char *key)
{
	JSHandle jsonHanlde;
	Json::Value& refJson = m_jsonValue->operator [](key);
	jsonHanlde.m_jsonValue = &refJson;	
	return jsonHanlde;
}

JSHandle JSHandle::operator[](const wchar_t *key)
{
	JSHandle jsonHanlde;
	
	if (IsValidString(key))
	{
		std::string strA = EDBASE::w2u(key);
		Json::Value& refJson = m_jsonValue->operator [](strA.c_str());
		jsonHanlde.m_jsonValue = &refJson;	
	}
	return jsonHanlde;
}

JSObject JSHandle::remove(const char* key)
{
	JSObject retJson;
	m_jsonValue->removeMember(key).swap(*retJson.m_jsonValue);
	return retJson;
}

bool JSHandle::hasKey(const char *key) const
{
	return m_jsonValue->isMember(key);
}

std::vector<std::string> JSHandle::memberNames() const
{
	if (!isArray())
	{
		return m_jsonValue->getMemberNames();
	}
	else
	{
		return std::vector<std::string>();
	}
}

JSObject::JSObject(JsonType jsonType/* = JsonNull*/)
{
	Json::Value*& jsonRef = const_cast<Json::Value*&>(m_jsonValue);
	jsonRef = new Json::Value((Json::ValueType)jsonType);
}

JSObject::JSObject(bool data)
{
	Json::Value*& jsonRef = const_cast<Json::Value*&>(m_jsonValue);
	jsonRef = new Json::Value(data);
}

JSObject::JSObject(int data)
{
	Json::Value*& jsonRef = const_cast<Json::Value*&>(m_jsonValue);
	jsonRef = new Json::Value(data);
}

JSObject::JSObject(unsigned int data)
{
	Json::Value*& jsonRef = const_cast<Json::Value*&>(m_jsonValue);
	jsonRef = new Json::Value(data);
}

JSObject::JSObject(double data)
{
	Json::Value*& jsonRef = const_cast<Json::Value*&>(m_jsonValue);
	jsonRef = new Json::Value(data);
}

JSObject::JSObject(const char* data)
{
	Json::Value*& jsonRef = const_cast<Json::Value*&>(m_jsonValue);
	jsonRef = new Json::Value(data);
}

JSObject::JSObject(const char* beginValue, const char *endValue)
{
	Json::Value*& jsonRef = const_cast<Json::Value*&>(m_jsonValue);
	jsonRef = new Json::Value(beginValue, endValue);
}

JSObject::JSObject(const JSObject& src)
{
	Json::Value*& jsonRef = const_cast<Json::Value*&>(m_jsonValue);
	jsonRef = new Json::Value((Json::ValueType)JsonNull);

	if (src.m_jsonValue)
	{
		m_jsonValue->operator = (*src.m_jsonValue);
	}
}

JSObject::JSObject(const JSHandle& src)
{
	Json::Value*& jsonRef = const_cast<Json::Value*&>(m_jsonValue);
	jsonRef = new Json::Value((Json::ValueType)JsonNull);
	//
	const JSObject& refSrc = static_cast<const JSObject&>(src);
	if (refSrc.m_jsonValue) 
	{
		m_jsonValue->operator = (*refSrc.m_jsonValue);
	}
}

JSObject::~JSObject()
{
	if (m_jsonValue)
	{
		delete m_jsonValue;
		m_jsonValue = NULL;
	}
}

JSObject& JSObject::operator=(const JSObject& src)
{
	m_jsonValue->operator = (*src.m_jsonValue);
	return *this;
}

JSObject& JSObject::operator=(const JSHandle& src)
{
	const JSObject& refSrc = static_cast<const JSObject&>(src);
	if (refSrc.m_jsonValue)
	{
		m_jsonValue->operator = (*refSrc.m_jsonValue);
	} 
	else 
	{
		m_jsonValue->clear();
	}
	return *this;
}

bool JSObject::jsonWrite(std::string* josnStringUTF8String)
{
	if (NULL == josnStringUTF8String) return false;
	Json::FastWriter jsonWriter;
	const char* pszJsonString = jsonWriter.write(*m_jsonValue);


	if (IsValidString(pszJsonString)) 
	{
		josnStringUTF8String->assign(pszJsonString);
	}
	else 
	{
		josnStringUTF8String->assign("");
	}
	return true;
}


bool JSObject::jsonWrite(std::wstring* josnStringW)
{

	if (NULL == josnStringW) return false;
	Json::FastWriter jsonWriter;
	const char* pszJsonString = jsonWriter.write(*m_jsonValue);

	if (IsValidString(pszJsonString))
	{
		std::wstring strW = EDBASE::u2w(pszJsonString);
		josnStringW->assign(strW.c_str());
	} 
	else 
	{
		josnStringW->assign(L"");
	}
	return true;
}

bool JSObject::jsonParse(const char* beginDoc, const char* endDoc/* = NULL*/)
{
	bool bSuccess = false;
	if (IsValidString(beginDoc))
	{
		if (NULL == endDoc) endDoc = beginDoc + strlen(beginDoc);
		Json::Reader jsonReader;
		bSuccess = jsonReader.parse(beginDoc, endDoc, *m_jsonValue);
	}
	return bSuccess;
}

bool JSObject::jsonParse(LPCWSTR beginDoc, LPCWSTR endDoc/* = NULL*/)
{
	bool bSuccess = false;
	if (IsValidString(beginDoc))
	{
		std::string strUTF8;
		if (NULL == endDoc) 
		{
			strUTF8 = EDBASE::w2u(beginDoc);
		}
		else 
		{
			std::wstring strW;
			strW.assign(beginDoc, endDoc);
			strUTF8 =  EDBASE::w2u(strW.c_str());
		}
		Json::Reader jsonReader;
		bSuccess = jsonReader.parse(strUTF8.c_str(), strUTF8.c_str() + strUTF8.size(), *m_jsonValue);
	}
	return bSuccess;
}

bool JSObject::jsonParse(const std::string& jsonString)
{
	bool bSuccess = false;
	if (!jsonString.empty())
	{
		Json::Reader jsonReader;
		bSuccess = jsonReader.parse(jsonString, *m_jsonValue);
	}

	return bSuccess;
}

bool JSHandle::toBytes(unsigned char* pBuffer, int& nSize) const
{
	if (isBytes() == false)
		return false;

	bool bRet = false;
	int nNeedSize = 0;
	LPCSTR pszBase64 = m_jsonValue->asCString();
	if (pszBase64 == NULL || strlen(pszBase64) <= 0)
	{
		nSize = 0;
		bRet = true;
	}
	else
	{
		nNeedSize = strlen(pszBase64);
		nNeedSize = (nNeedSize>>2)*3;
		if (NULL == pBuffer)
		{
			nSize = nNeedSize;
			bRet = true;
		}
		else if (nSize >= nNeedSize)
		{
			std::string	strBase64 = pszBase64;
			EDBASE::Base64Decode(strBase64, pBuffer, nSize);
			bRet = true;
		}
		else
		{
			bRet = false;
		}
	}
	return bRet;
}
